#ifndef CHROMOSOME_H_
#define CHROMOSOME_H_

#include <QVariant>
#include <QDebug>

/**
  * Class that represents abstract chromosome.
  * @author Łukasz Szybka
  */
class Chromosome
{
public:
    /**
      * Determines how to compare chromosomes
      * When true chromosome with smaller fitness is better
      * When false chromosome with greater fitness is better
      */
    static bool minimize;

    /**
      * Destructor
      */
    virtual ~Chromosome();

    /**
      * Operator=
      */
    Chromosome& operator=(const Chromosome& other);

    /**
      * Sets Chromosome::fitness
      * @param _fitness New value
      */
    void setFitness(double _fitness);
    /**
      * Gets Chromosome::fitness
      * @return Chromosome::fitness value
      */
    double getFitness() const;
    /**
      * Sets random bits in all chromosome
      * If chromosome length is 0 does nothing
      */
    virtual void setRandom() = 0;
    /**
      * Performs crossing over with other chromosome
      * Crossing over point is choosen randomly
      * Sets child chromosome fitness to 0
      * Aborts when chromosome lenght is different
      * @param partner Chromosome that will take part in crossing over
      */
    virtual void crossOver(const Chromosome& partner) = 0;
    /**
      * Performs mutation on 1 position
      * Mutation position is choosen randomly
      */
    void mutate();

    /**
      * Mutates chromosome on 1 position
      * @param index Position index to mutate
      */
    virtual void mutate(int index) = 0;

    /**
      * Calls additional operators that uses only one chromosome.
      * Should be implemented when inherited.
      * Does nothing here.
      */
    virtual void additionalOperators(int position);
    /**
      * Calls additional operators that needs another chromosome.
      * Should be implemented when inherited.
      * @param second Second chromosome needed to perform operators.
      */
    virtual void additionalOperators(const Chromosome& second);
    /**
      * Compares 2 chromosomes by Chromosome::fitness
      * @param other Chromosome to compare with
      * @return True when this->fitness < other.fitness, otherwize False
      */
    bool operator<(const Chromosome& other) const;

    virtual bool operator==(const Chromosome& other) const = 0;
    /**
      * Used by operator<<
      * @return String that contains all bits in chromosome.
      */
    virtual QString toString() const = 0;

    /**
      * Creates chromosome which is exact duplicate of this chromosome
      * Pointer should be deleted by caller
      * @return Pointer to duplicate
      */
    virtual Chromosome* duplicate() const = 0;
    /**
      * @param index Position in chromosome data
      * @return Chromosome data at specified position as QVariant
      */
    virtual QVariant at(int index) const = 0;
    /**
      * @return Chromosome data as QVariant
      */
    virtual QVariant data() const = 0;
    /**
      * @return Chromosome length
      */
    virtual int size() const = 0;

    /**
      * Compares 2 chromosomes by fitness
      * Uses Chromosome::minimize to determine which chromosome is better
      * @return True when chr1 is better than chr2
      */
    static bool greaterThan(const Chromosome* chr1, const Chromosome* chr2);

    /**
      * Prints all chromosome data, fitness and lenght
      */
    friend QDebug operator<<(QDebug dbg, const Chromosome& chr);

protected:
    /**
      * Constructor
      */
    Chromosome();
    /**
      * Copy constructor
      */
    Chromosome(const Chromosome &other);
    /**
      * Defines chromosome fitness
      */
    double fitness;

private:
};

#endif /*CHROMOSOME_H_*/
